The Java 2 Platform Standard Edition (J2SE) and the Java Development Kit (JDK) provide developers with access to a wide range of user interface (UI) and graphical user interface (GUI) components. The JDK provides flexibility and control over the appearance of UIs and GUIs.
Conventional graphics toolkits, such as the Abstract Windowing Toolkit (AWT), provide application programming interfaces (APIs) for applications. The Java Foundation Classes (JFC), also commonly referred to as “Swing” or the “Swing toolkit,” are a set of Java class libraries having components that build upon the AWT by providing additional UI and GUI components and services. The Swing toolkit incorporates the AWT and is included in the JDK and J2SE to provide a rich, extensible GUI component library. The Swing toolkit is implemented in the Java programming language, and enables building of applications with GUIs and graphics functionality that can run on any platform supporting the J2SE, such as Microsoft Windows, Linux, and Mac OS X.
The Swing toolkit includes categories of components: atomic controls, complex data components, text components, menu components, layout containers and top-level window components. Examples of Swing components include buttons, panels, listboxes and checkboxes. In addition to the new components, the Swing toolkit offers a customizable look and feel that allows the components to take on the appearance of various windowing systems, or their own unique look and feel. For instance, Swing allows applications to easily convert from a “Java look and feel” to a “Windows look and feel.” Developers have the ability to create their own look and feel for custom applications. Regardless of the desired look and feel, a consistent API can be maintained for the component. Thus, developers can code their application GUI once and run it in multiple look and feels.
Swing is not designed for multi-threading. Access to a Swing component or class has to occur from a single thread, specifically an event dispatch thread (EDT). Thus, once a Swing component has been realized (e.g., when the component's “paint” method has been called), all code that might affect or depend on the state of that component should be executed on the EDT. The EDT is responsible for processing all UI and GUI related events, such as user interactions (e.g., mouse clicks, key presses), notification of listeners of user input, and all painting and graphics including repainting dirty regions or updated areas. Essentially every instruction to change something or request something from the Swing component is executed as an event on the EDT.
The EDT handles many different events, as described above. At the EDT, all of the events or tasks are queued and processed sequentially. Problems can occur when too many events are queued. If one event takes a long time to process on the EDT, such as loading an HTML page, all of the other events in the queue will have to wait to be processed. This waiting or delay is undesirable. It is generally perceived as the entire UI and application itself being unresponsive, often referred to as “freezing” or “blocking.”
Conventional techniques for attempting to reduce freezing or blocking include two Swing utilities. These Swing utilities are java.awt.EventQueue.invokeLater, used for asynchronous method calls, and java.awt.EventQueue.invokeandWait for synchronous calls. However, the methods java.awt.EventQueue.invokeLater and java.awt.EventQueue.invokeandWait create runnable classes for every call to those methods. Each runnable class is executed as a separate event on the EDT. Creating new runnable classes for every call is computationally expensive, and often results in the same freezing or blocking problem described above when many runnable classes are passed to the EDT.
Lengthy tasks are computational operations requiring a long time, that is, more than a nominal amount of time, to process. As used herein, anything more than a fraction of a second generally constitutes a “long time.” Examples of lengthy tasks include various calculations, class loading, class initialization, blocking for data networks such as the Internet, disk access operations, and loading HTML documents from the Internet for display on a GUI. Because lengthy tasks are time-consuming, they are desirably processed as background processes separate and apart from the EDT. Otherwise, sending lengthy tasks to the EDT could result in unacceptable freezing situations. That is, all of the regular tasks to be scheduled on the EDT such as painting, responding to mouse movements, processing button events, and application resizing, would have to wait until the lengthy task was completed.
In some cases, lengthy tasks require interaction with Java Swing components. Handling of these lengthy tasks can be particularly troubling. On the one hand, it is desirable to process the lengthy task as a background process, because of its time-consuming nature. On the other hand, the general rule is that Swing components have to be accessed from the EDT only.
SwingWorker is an abstract class that can be subclassed to perform GUI-related work in a dedicated thread. The conventional SwingWorker class is implemented in SwingWorker.java, and is publicly available for download. SwingWorker provides the mechanism for implementing lengthy tasks as background processes, i.e., background threads.
To use the conventional SwingWorker class, a developer first creates a subclass of it. In the subclass, a construct( ) method is implemented so that the subclass contains the code to perform the lengthy task. When the SwingWorker subclass is instantiated, SwingWorker creates a thread but does not start it. The developer invokes start( ) on the SwingWorker object to start the thread, which then calls the construct( ) method. When the object returned by the construct( ) method is needed, the SwingWorker's get( ) method is called. The following is one example of using SwingWorker:
. . . //in the main method:  final SwingWorker worker =    new SwingWorker( ) {      public Object construct( ) {        return new          expensiveDialogComponent( );      }  };  worker.start( );. . . //in an action event handler:  JOptionPane.showMessageDialog      (f, worker.get( ));
When the program's main( ) method invokes the start( ) method, SwingWorker starts a new thread that instantiates ExpensiveDialogComponent. The main( ) method also constructs a GUI that consists of a window with a button. When the user clicks the button, the program blocks, if necessary, until the ExpensiveDialogComponent has been created. The program then shows a modal dialog containing the ExpensiveDialogComponent. You can find the entire program in MyApplication.java.
With conventional implementations of SwingWorker, it is generally only possible to deliver the final result or output of a lengthy task to the EDT. Intermediate results and state information, provided before the final result is provided, cannot be delivered. Thus, a user has to wait for the final result. For instance, when downloading a document, a user must wait for the entire document (final result) to be downloaded, even though certain data within the document such as images, text, and other objects (partial results) are downloaded in the interim. Waiting in this manner can be frustrating for the user who is more concerned with the partial results, i.e., parts of the final document, or at least some state information describing the progress or status of the document download.
Efficient techniques are needed for accessing Swing components from outside of the EDT, including calling methods requiring execution of events on the EDT from outside of the EDT, and executing lengthy tasks which need to interact with a UI using the EDT.